# simulator/sim_engine.py
"""
仿真引擎 - 负责调用雷达模拟器和环境回波模拟器，同时负责更新场景参数
Simulation Engine - Manages radar and echo simulators, updates scene parameters
"""

import numpy as np
import json
import time
from typing import Dict, List, Tuple, Any
from datetime import datetime
from config.config import RADAR_DEFAULT_PARAMS, SIMULATION_PARAMS

class Target:
    def __init__(self, target_id: str, position: Tuple[float, float, float],
                 velocity: Tuple[float, float, float] = (0.0, 0.0, 0.0), rcs: float = 1.0):
        self.id = target_id
        self.position = np.array(position, dtype=np.float64)  # (x, y, z) in km
        self.velocity = np.array(velocity, dtype=np.float64)  # (vx, vy, vz) in m/s
        self.rcs = rcs  # Radar Cross Section in m²
        self.detected = False
        self.detection_history = []

    def update_position(self, dt: float):
        """更新目标位置

        Args:
            dt: 时间增量 (秒)
        """
        # velocity单位是m/s，position单位是km，所以需要除以1000
        self.position = self.position + self.velocity * dt / 1000.0  # convert m/s to km/s
        
    def get_range_azimuth_elevation(self, radar_pos: np.array) -> Tuple[float, float, float]:
        """计算目标相对雷达的距离、方位角、仰角"""
        relative_pos = self.position - radar_pos
        range_val = np.linalg.norm(relative_pos)
        azimuth = np.degrees(np.arctan2(relative_pos[1], relative_pos[0]))
        elevation = np.degrees(np.arcsin(relative_pos[2] / range_val)) if range_val > 0 else 0
        return range_val, azimuth, elevation

class WeatherCondition:
    def __init__(self, temperature: float = 15.0, humidity: float = 60.0, 
                 precipitation: float = 0.0, wind_speed: float = 10.0):
        self.temperature = temperature  # Celsius
        self.humidity = humidity        # %
        self.precipitation = precipitation  # mm/h
        self.wind_speed = wind_speed    # km/h
        
    def get_atmospheric_attenuation(self, frequency_ghz: float) -> float:
        """计算大气衰减因子 (dB/km)"""
        base_attenuation = 0.1
        humidity_factor = 1 + self.humidity / 100.0
        rain_factor = 1 + self.precipitation * 0.1
        return base_attenuation * humidity_factor * rain_factor

class SimEngine:
    """仿真引擎 - 统一管理雷达模拟器和回波模拟器"""

    def __init__(self, radar_params: Dict = None):
        self.params = radar_params or RADAR_DEFAULT_PARAMS.copy()
        self.radar_position = np.array([0.0, 0.0, 0.0])  # 雷达位置 (x, y, z) km
        self.targets = {}
        self.weather = WeatherCondition()
        self.simulation_time = 0.0
        self.detection_log = []
        self.is_running = False

        # 初始化雷达模拟器和回波模拟器
        self._init_simulators()

    def _init_simulators(self):
        """初始化雷达模拟器和回波模拟器"""
        try:
            from simulator.radar_moni import RadarMoni
            from simulator.echo_moni import EchoMoni

            self.radar_simulator = RadarMoni(self.params)
            self.echo_simulator = EchoMoni(self.params)

        except ImportError as e:
            # 兼容性处理：使用旧的类名
            try:
                from simulator.radar_moni import RadarSignalProcessor
                from simulator.echo_moni import EchoProcessor

                self.radar_simulator = RadarSignalProcessor(self.params)
                self.echo_simulator = EchoProcessor(self.params)
            except ImportError:
                print(f"无法导入模拟器组件: {e}")
                raise

    def add_target(self, target: Target):
        """添加目标"""
        self.targets[target.id] = target
        
    def remove_target(self, target_id: str):
        """移除目标"""
        if target_id in self.targets:
            del self.targets[target_id]
            
    def update_radar_params(self, new_params: Dict):
        """更新雷达参数"""
        self.params.update(new_params)
        
    def update_weather(self, weather_params: Dict):
        """更新天气条件"""
        for key, value in weather_params.items():
            if hasattr(self.weather, key):
                setattr(self.weather, key, value)

    def step_simulation(self, dt: float = None) -> Dict:
        """仿真步进 - 一个完整的雷达脉冲周期"""
        if dt is None:
            # 使用脉冲重复时间作为步进时间
            dt = self.params.get('pulse_repetition_time', 1.0) * 1e-3  # 转换为秒

        # 1. 雷达模拟器生成发射信号
        tx_data = self.radar_simulator.generate_transmit_signal()

        # 2. 准备当前目标状态
        current_targets = self._prepare_target_states()

        # 3. 回波模拟器生成三路回波信号（和、方位差、俯仰差）
        t_rx, sum_echo, az_diff_echo, el_diff_echo = self.echo_simulator.generate_echo_signal(tx_data, current_targets)

        # 4. 雷达信号处理（三路独立处理）
        # 三路信号分别进行：接收机增益 → 噪声 → 脉冲压缩 → 相参积累
        # signal_process 内部会处理：添加噪声 → 脉冲压缩 → 积累到矩阵 → (达到积累数时)生成RD图、检测和测角
        result = self.radar_simulator.signal_process(sum_echo, az_diff_echo, el_diff_echo)

        # 提取结果
        measurements = result.get('measurements', [])

        # 将测量结果转换为检测结果（保持兼容性）
        detections = []
        for meas in measurements:
            # 单脉冲模式的测量结果，需要添加目标ID（基于距离匹配）
            detection = {
                'range': meas['range'],
                'doppler': meas['doppler'],
                'velocity': meas['velocity'],
                'amplitude': meas['amplitude'],
                'snr_db': meas['snr'],
                'detected': True
            }

            # 尝试匹配最近的目标
            min_distance = float('inf')
            matched_target_id = None
            for target_state in current_targets:
                distance = abs(target_state['range'] - meas['range'])
                if distance < min_distance and distance < 5.0:  # 5km 匹配阈值
                    min_distance = distance
                    matched_target_id = target_state['id']

            if matched_target_id:
                detection['target_id'] = matched_target_id
                detection['azimuth'] = next(t['azimuth'] for t in current_targets if t['id'] == matched_target_id)
                detection['elevation'] = next(t['elevation'] for t in current_targets if t['id'] == matched_target_id)
                detection['rcs'] = next(t['rcs'] for t in current_targets if t['id'] == matched_target_id)
                detection['radial_velocity'] = meas['velocity']

                # 如果有测角结果，打印真实角度与测量角度的对比
                if 'azimuth_error' in meas and 'elevation_error' in meas:
                    true_azimuth = detection['azimuth']
                    true_elevation = detection['elevation']
                    measured_azimuth = meas['azimuth_error']
                    measured_elevation = meas['elevation_error']

                    # 获取天线增益（和通道）
                    sum_gain, az_diff_gain, el_diff_gain = self.echo_simulator._get_antenna_gain(true_azimuth, true_elevation)
                    sum_gain_db = 10 * np.log10(sum_gain) if sum_gain > 0 else -np.inf

                    print(f"[单脉冲测角对比] 目标ID={matched_target_id}:")
                    print(f"  【方位角】真实: {true_azimuth:.4f}° | 测量: {measured_azimuth:.4f}° | 误差: {abs(measured_azimuth - true_azimuth):.4f}°")
                    print(f"  【俯仰角】真实: {true_elevation:.4f}° | 测量: {measured_elevation:.4f}° | 误差: {abs(measured_elevation - true_elevation):.4f}°")
                    print(f"  【天线增益】和通道: {sum_gain_db:.2f} dB (线性值: {sum_gain:.4f})")

            detections.append(detection)

        # 整合信号数据
        signal_data = {
            'tx_time': tx_data.time_axis,
            'tx_signal': tx_data.iq_samples,
            'rx_time': t_rx,
            'rx_signal': sum_echo,  # 和通道回波信号（干净的，噪声在接收机中添加）
            'sum_echo': sum_echo,  # 和通道回波
            'az_diff_echo': az_diff_echo,  # 方位差通道回波
            'el_diff_echo': el_diff_echo,  # 俯仰差通道回波
            'receiver_signal': result.get('receiver_signal'),  # 接收机信号（叠加热噪声后的回波信号）
            'tx_data': tx_data,  # 包含完整的发射信号结构
            'compressed_signal': result.get('compressed_signal'),  # 脉冲压缩信号（包含噪声影响）
            'accumulated_pulses': result.get('accumulated_pulses', 0),
            'coherent_integration_complete': result.get('coherent_integration_complete', False),
            'radar_mode': result.get('radar_mode', 'search'),  # 雷达工作模式
            'target_detected_range': result.get('target_detected_range')  # 检测到的目标距离
        }

        # 如果完成了相参积累，添加RD图数据
        if result.get('coherent_integration_complete', False):
            signal_data['rd_map'] = result.get('rd_map')
            signal_data['range_axis'] = result.get('range_axis')
            signal_data['doppler_axis'] = result.get('doppler_axis')
            signal_data['pulse_compression_matrix'] = result.get('pulse_compression_matrix')  # RD图输入矩阵

        # 简单更新目标检测状态
        for target in self.targets.values():
            target.detected = False

        for detection in detections:
            target_id = detection.get('target_id')
            if target_id and target_id in self.targets:
                target = self.targets[target_id]
                target.detected = True
                target.detection_history.append(detection)

        # 更新仿真时间
        self.simulation_time += dt

        # 更新目标位置到下一个时刻
        for target in self.targets.values():
            target.update_position(dt)

        # 记录检测结果
        if detections:
            # 为检测结果添加时间戳
            for detection in detections:
                detection['timestamp'] = self.simulation_time
            self.detection_log.extend(detections)

        simulation_state = {
            'simulation_time': self.simulation_time,
            'detections': detections,
            'measurements': measurements,  # 添加measurements键以保持与GUI的兼容性
            'targets_count': len(self.targets),
            'current_targets': current_targets,
            'signal_data': signal_data,
            'weather': {
                'temperature': self.weather.temperature,
                'humidity': self.weather.humidity,
                'precipitation': self.weather.precipitation
            }
        }

        return simulation_state

    def _prepare_target_states(self) -> List[Dict]:
        """准备当前目标状态信息"""
        current_targets = []
        for target in self.targets.values():
            # 计算当前目标相对雷达的参数
            range_val_km, azimuth, elevation = target.get_range_azimuth_elevation(self.radar_position)

            # 转换距离单位：km → m（仿真内部统一使用米）
            range_val = range_val_km * 1000  # m

            # 计算径向速度
            position_vector = target.position - self.radar_position
            velocity_vector = target.velocity  # 已经是m/s，不需要转换！

            if np.linalg.norm(position_vector) > 0:
                radial_unit = position_vector / np.linalg.norm(position_vector)
                radial_velocity = np.dot(velocity_vector, radial_unit)
            else:
                radial_velocity = 0

            current_targets.append({
                'id': target.id,
                'range': range_val,  # m (仿真内部单位)
                'azimuth': azimuth,
                'elevation': elevation,
                'radial_velocity': radial_velocity,  # m/s
                'rcs': target.rcs,
                'position': target.position.copy(),
                'velocity': target.velocity.copy()
            })

        return current_targets

    def get_simulation_status(self) -> Dict:
        """获取仿真状态"""
        detected_targets = sum(1 for t in self.targets.values() if t.detected)
        
        return {
            'simulation_time': round(self.simulation_time, 2),
            'total_targets': len(self.targets),
            'detected_targets': detected_targets,
            'detection_rate': detected_targets / len(self.targets) if self.targets else 0,
            'total_detections': len(self.detection_log),
            'radar_params': self.params.copy(),
            'weather_conditions': {
                'temperature': self.weather.temperature,
                'humidity': self.weather.humidity,
                'precipitation': self.weather.precipitation,
                'wind_speed': self.weather.wind_speed
            },
            'is_running': self.is_running
        }
        
    def reset_simulation(self):
        """重置仿真"""
        self.simulation_time = 0.0
        self.detection_log.clear()
        for target in self.targets.values():
            target.detected = False
            target.detection_history.clear()
        self.is_running = False
        
    def export_detection_data(self) -> str:
        """导出检测数据为JSON格式"""
        export_data = {
            'simulation_metadata': {
                'total_time': self.simulation_time,
                'radar_params': self.params,
                'export_timestamp': datetime.now().isoformat()
            },
            'detections': self.detection_log,
            'targets_summary': [
                {
                    'id': target.id,
                    'position': target.position.tolist(),
                    'velocity': target.velocity.tolist(),
                    'rcs': target.rcs,
                    'detection_count': len(target.detection_history)
                }
                for target in self.targets.values()
            ]
        }
        return json.dumps(export_data, indent=2, ensure_ascii=False)


# 保持向后兼容性：RadarEngine 是 SimEngine 的别名
RadarEngine = SimEngine